#include "SceneBuilder.h"
#include "Scene.h"
#include "SceneObj.h"
#include "DecoArticulatedBody.h"
#include "DecoRigidBody.h"
#include "ParticleSys.h"
#include "CSRMatrix.h"
#include "FluidSparseMatrix.h"
#include "FluidSparseVector.h"
#include "PCGSolver.h"
#include "mkl_blas.h"
#include "mkl_spblas.h"
#include "Scene.h"
#include "SearcherConfig.h"
#include "DecoLogger.h"


tbb::mutex SceneBuilder::msMutex;
SceneBuilder* SceneBuilder::msSceneBuilder;

SceneBuilder* SceneBuilder::GetSingleton()
{
	tbb::mutex::scoped_lock lock(msMutex);
	if (!msSceneBuilder)
		msSceneBuilder = new SceneBuilder();
	return msSceneBuilder;

}

void SceneBuilder::DestroySingleton()
{
	tbb::mutex::scoped_lock lock(msMutex);
	if (msSceneBuilder)
		delete msSceneBuilder;
}

void SceneBuilder::ConstructSceneWithoutDestroy(DecoScene* scene)
{
 	tbb::mutex::scoped_lock lock(DecoScene::msMutex);
	const SceneBuilderInfo& info = DecoConfig::GetSingleton()->GetSceneBuilderInfo();
	Box ScnBox = info.mSceneBox;
//	const Box ScnBox(vector3(-2, -1, -1), vector3(2, 1, 1));
	scene->SetSceneBox(ScnBox);
	scene->Reset();
	//DecoArticulatedObject* pObj = scene->GetArticulatedObject();
	////pObj->Reset();
	//delete pObj; //tanjie potential memory leak...
	scene->EraseAllSceneObject();

	std::string pathName = info.mModelFileName;
//	string pathName = "../models/swim/fish4Link.skel";
	DecoArticulatedObject* pObj = DecoArticulatedObject::CreateFromMesh(pathName);
	pObj->SetSimulationType(AST_General);
	scene->AddSceneObject(pObj);

	GridField* grid = scene->GetGrid();

	EnforceSolidSceneWhenUpdate(scene);
	int numX = grid->numXElement;
	int numY = grid->numYElement;
	int numZ = grid->numZElement;

	for (int i = 0; i < numX; ++i)
	{
		for (int j = 0; j < numY; ++j)
		{
			for (int k = 0; k < numZ; ++k)
			{
				grid->u[i][j][k] = 0;
				grid->u[i + 1][j][k] = 0;
				grid->v[i][j][k] = 0;
				grid->v[i][j + 1][k] = 0;
				grid->w[i][j][k] = 0;
				grid->w[i][j][k + 1] = 0;
			}
		}
	}
	scene->VoxelizeSolid();
	scene->solver.UpdateFluidGridType(true);
}


void SceneBuilder::ConstructScene(DecoScene* scene)
{
	const SceneBuilderInfo& info = DecoConfig::GetSingleton()->GetSceneBuilderInfo();
	Box ScnBox = info.mSceneBox;
	int xElements = info.mResolution;
//	const int xElements = 64;
//	const Box ScnBox(vector3(-2, -1, -1), vector3(2, 1, 1));

	scene->SetSceneBox(ScnBox);
	scene->SetNumXElement(xElements);
	scene->AllocateTempBuffer();
	scene->SetGridsInformation();
	GridField* grid = scene->GetGrid();
	scene->EraseAllSceneObject();

	tbb::mutex::scoped_lock lock(DecoScene::msMutex);
	std::string pathName = info.mModelFileName;
//	string pathName = "../models/swim/fish4Link.skel";
	DecoArticulatedObject* pObj = DecoArticulatedObject::CreateFromMesh(pathName);

	pObj->SetSimulationType(AST_General);
	scene->AddSceneObject(pObj);


	EnforceSolidSceneWhenUpdate(scene);
	int numX = grid->numXElement;
	int numY = grid->numYElement;
	int numZ = grid->numZElement;

	for (int i = 0; i < numX; ++i)
	{
		for (int j = 0; j < numY; ++j)
		{
			for (int k = 0; k < numZ; ++k)
			{
				grid->u[i][j][k] = 0;
				grid->u[i + 1][j][k] = 0;
				grid->v[i][j][k] = 0;
				grid->v[i][j + 1][k] = 0;
				grid->w[i][j][k] = 0;
				grid->w[i][j][k + 1] = 0;
			}
		}
	}
	scene->ResetCurrentTime();
	scene->VoxelizeSolid();
	scene->solver.UpdateFluidGridType(true);
	double vol = scene->CollisionDetection();

	(*DecoLogger::GetSingleton()) << "Collision Volume is " << vol << ".\n";
}

void SceneBuilder::EnforceSolidSceneWhenUpdate(DecoScene* scene)
{
	const SceneBuilderInfo& info = DecoConfig::GetSingleton()->GetSceneBuilderInfo();
	GridField* grid = scene->GetGrid();
	int numX = grid->numXElement;
	int numY = grid->numYElement;
	int numZ = grid->numZElement;
	int middleCell = numZ / 2;
	static bool bFirstTime = false;

	if (info.mSimulationDim == 2)
	{
		for (int i = 0; i < numX; ++i)
		{
			for (int j = 0; j < numY; ++j)
			{
				for (int k = 0; k < numZ; ++k)
				{
					//if (abs(k - middleCell) > 16)
					if (k != middleCell && k != middleCell - 1)
					{
						grid->SetCellType(i, j, k, GT_Solid);
						grid->u[i][j][k] = 0;
						grid->u[i + 1][j][k] = 0;
						grid->v[i][j][k] = 0;
						grid->v[i][j + 1][k] = 0;
						grid->w[i][j][k] = 0;
						grid->w[i][j][k + 1] = 0;

					}
					//else
					//{
					//	//if (j == 0 || i == 0 || i == numX - 1 || k == 0 || k == numZ - 1)
					//	//	grid->SetCellType(i, j, k, GT_Solid);

					//}
				}
			}
		}
	}
	if (bFirstTime)
	{
#ifdef _PARTICLE_SYS
		scene->particles.FillParticles();
#endif
		bFirstTime = false;
	}

}

SceneBuilder::SceneBuilder()
{

}
SceneBuilder::~SceneBuilder()
{

}
